package com.naiterui.ehp.bs.search.service.impl.core;

import com.naiterui.ehp.bp.support.exception.BusinessException;
import com.naiterui.ehp.bs.search.config.EsProperties;
import com.naiterui.ehp.bs.search.exception.ExceptionCodes;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.admin.indices.alias.Alias;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.Arrays;

/**
 * @author guoyongxiang
 * @date 2019-08-27 15:20
 * @since 1.0.0
 */
@Service
public class EsIndicesService {

    private static final Logger LOGGER = LoggerFactory.getLogger(EsIndicesService.class);

    public static final int INDEX_NUMBER_OF_SHARDS = 5;

    /**
     * 搜索服务注入
     */
    @Autowired
    private RestHighLevelClient esClient;
    @Autowired
    private EsProperties esProperties;

    /**
     * 创建索引
     * BaseIndexService.createIndex()
     *
     * @param indexName
     * @Author guoyongxiang
     * @Date 2016年8月5日
     * @since 1.0.0
     */
    public void createIndex(String indexName) throws BusinessException {
        this.createIndex(indexName, null);
    }

    public CreateIndexResponse create(CreateIndexRequest createIndexRequest) throws BusinessException {
        try {
            return esClient.indices().create(createIndexRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            LOGGER.error("创建索引异常 createIndexRequest:{}", createIndexRequest, e);
            throw new BusinessException(ExceptionCodes.INDICES_CREATE_FAILED);
        }
    }

    /**
     * 创建索引
     * BaseIndexService.createIndex()
     *
     * @param indexName
     * @Author guoyongxiang
     * @Date 2016年8月5日
     * @since 1.0.0
     */
    void createIndex(String indexName, String aliasName) throws BusinessException {
        CreateIndexRequest request = this.getCreateIndexBuilder(indexName);
        if (!StringUtils.isEmpty(aliasName)) {
            request.alias(new Alias(aliasName));
        }
        try {
            esClient.indices().create(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            LOGGER.error("创建索引异常 indexName:{}", indexName, e);
            throw new BusinessException(ExceptionCodes.INDICES_CREATE_FAILED);
        }
    }

    public void createIndexSetSource(String indexName, XContentBuilder source) throws BusinessException {
        CreateIndexRequest createIndexRequest = this.getCreateIndexBuilder(indexName).source(source);
        try {
            esClient.indices().create(createIndexRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            LOGGER.error("创建索引异常 indexName:{}", indexName, e);
            throw new BusinessException(ExceptionCodes.INDICES_CREATE_FAILED);
        }
    }

    public void createIndexSetSource(String indexName, XContentBuilder settings, XContentBuilder mappings) throws BusinessException {
        CreateIndexRequest createIndexRequest = this.getCreateIndexBuilder(indexName).settings(settings).mapping(mappings);
        try {
            esClient.indices().create(createIndexRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            LOGGER.error("创建索引异常 indexName:{}", indexName, e);
            throw new BusinessException(ExceptionCodes.INDICES_CREATE_FAILED);
        }
    }

    /**
     * 创建索引
     * BaseIndexService.createIndex()
     *
     * @param indexName
     * @Author guoyongxiang
     * @Date 2016年8月5日
     * @since 1.0.0
     */
    public void createIndex(CreateIndexRequestBuilder builder, String indexName, String aliasName) {
        builder.addAlias(new Alias(aliasName)).execute().actionGet();
    }

    @SafeVarargs
    public final CreateIndexRequest getCreateIndexBuilder(String indexName, Settings... settings) {

        CreateIndexRequest request = new CreateIndexRequest(indexName);
        Settings.Builder builder = Settings.builder().put("index.number_of_shards", INDEX_NUMBER_OF_SHARDS)
                .put("index.number_of_replicas", esProperties.getReplicasNum());
        if (settings != null && settings.length > 0) {
            Arrays.stream(settings).forEachOrdered(builder::put);
        }
        request.settings(builder);
        return request;
    }

    /**
     * 删除索引
     * BaseIndexService.deleteIndex()
     *
     * @param indexName
     * @Author guoyongxiang
     * @Date 2016年8月3日
     * @since 1.0.0
     */
    public void deleteIndex(String... indexName) throws BusinessException {
        DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(indexName);
        try {
            this.esClient.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            LOGGER.error("索引删除失败 indexName:{}", indexName);
            throw new BusinessException(ExceptionCodes.INDICES_DEL_FAILED, e);
        }
    }

    /**
     * 切换别名并删除旧索引
     * BaseIndexService.replaceAliasAndDeleteIndex()
     *
     * @param oldIndexName
     * @param newIndexName
     * @param aliasName
     * @Author guoyongxiang
     * @Date 2016年8月3日
     * @since 1.0.0
     */
    public void replaceAliasAndDeleteIndex(String oldIndexName, String newIndexName, String aliasName) throws BusinessException {
        this.replaceAlias(oldIndexName, newIndexName, aliasName);
        this.deleteIndex(oldIndexName);
    }

    /**
     * 创建索引别名  TODO 待测试
     * SearchDoctorServiceImpl.addAlias()
     *
     * @param indexName
     * @param aliasName
     * @Author guoyongxiang
     * @Date 2016年7月27日
     * @since 1.0.0
     */
    public void addAlias(String indexName, String aliasName) throws BusinessException {
        CreateIndexRequest createIndexRequest = new CreateIndexRequest(indexName);
        createIndexRequest.alias(new Alias(aliasName));
        try {
            esClient.indices().create(createIndexRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            LOGGER.error("创建索引别名异常 indexName:{}, aliasName:{}", indexName, aliasName, e);
            throw new BusinessException(ExceptionCodes.INDICES_ALIAS_CREATE_FAILED);
        }
    }

    /**
     * 替换别名索引
     * SearchDoctorServiceImpl.replaceAlias()
     *
     * @param oldIndexName
     * @param newIndexName
     * @param aliasName
     * @Author guoyongxiang
     * @Date 2016年7月27日
     * @since 1.0.0
     */
    private void replaceAlias(String oldIndexName, String newIndexName, String aliasName) throws BusinessException {
        IndicesAliasesRequest indicesAliasesRequest = new IndicesAliasesRequest();
        indicesAliasesRequest.addAliasAction(IndicesAliasesRequest.AliasActions.remove().index(oldIndexName).alias(oldIndexName));
        indicesAliasesRequest.addAliasAction(IndicesAliasesRequest.AliasActions.add().index(newIndexName).alias(oldIndexName));

        try {
            this.esClient.indices().updateAliases(indicesAliasesRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            LOGGER.error("索引替换别名异常 oldIndexName:{}, newIndexName:{}, aliasName:{}", oldIndexName, newIndexName, aliasName, e);
            throw new BusinessException(ExceptionCodes.INDICES_OPERATION_FAILED);
        }

    }

    /**
     * 判断索引是否存在
     * BaseIndexService.indexExists()
     *
     * @param indexName
     * @return
     * @Author guoyongxiang
     * @Date 2016年8月3日
     * @since 1.0.0
     */
    public Boolean indexExists(String indexName) throws BusinessException {
        GetIndexRequest getIndexRequest = new GetIndexRequest(indexName);
        try {
            return this.esClient.indices().exists(getIndexRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            LOGGER.error("索引信息查询失败 indexName:{}", indexName, e);
            throw new BusinessException(ExceptionCodes.INDICES_GET_FAILED);
        }
    }

}
